#include "predicates.h"
#include "prover.h"
#include "system.h"
#include "try.h"

// I couldn't say singlog code is exception-safe...
// But C++ try/catch is the only way to do it.

class tryCall : public OnceBindTupleProver {
predicateName("try")
  tryCall () :
    prover (0) {
  }
  ~tryCall () {
    if(prover)
      delete prover;
  }

  bool proveOnce () {
    binder.capture (system->trail);
    prover = Prover::create (*tuple->nodes[1], *system);
    bool ret;

    try {
      ret = prover->prove ();
    } catch(RaisedException ex) {
      binder.undo (system->trail);
      int lastCatch = tuple->nodes.size () - 3, n = 2;

      while(n <= lastCatch) {
        Node &catchFinal = *tuple->nodes[n].final ();
        if(catchFinal.type () != Atom::ID
            || static_cast<Atom&> (catchFinal).name != "catch")
          return false; // Illegal construct

        if(binder.bind (*tuple->nodes[n + 1], *ex.node, system->trail)) {
          delete prover;
          prover = Prover::create (*tuple->nodes[n + 2], *system);
          return prover->prove ();
        }

        n += 3;
      }

      throw ; // No handler catching it, bail out
    }

    return ret;
  }

  Prover *prover;
};

ProverFactoryRegistrar<tryCall, Tuple::ID> tryRegistrar;

class raiseCall : public OnceBindTupleProver {
predicateName("raise")

  bool proveOnce () {
    throw RaisedException (tuple->nodes[1].node->final ());
  }
};

ProverFactoryRegistrar<raiseCall, Tuple::ID, 2> raiseRegistrar;
